package com.jcbase.core.weixin;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.StrKit;
import com.jfinal.weixin.sdk.msg.in.InImageMsg;
import com.jfinal.weixin.sdk.msg.in.InLinkMsg;
import com.jfinal.weixin.sdk.msg.in.InLocationMsg;
import com.jfinal.weixin.sdk.msg.in.InMsg;
import com.jfinal.weixin.sdk.msg.in.InShortVideoMsg;
import com.jfinal.weixin.sdk.msg.in.InTextMsg;
import com.jfinal.weixin.sdk.msg.in.InVideoMsg;
import com.jfinal.weixin.sdk.msg.in.InVoiceMsg;
import com.jfinal.weixin.sdk.msg.in.event.InCustomEvent;
import com.jfinal.weixin.sdk.msg.in.event.InFollowEvent;
import com.jfinal.weixin.sdk.msg.in.event.InLocationEvent;
import com.jfinal.weixin.sdk.msg.in.event.InMassEvent;
import com.jfinal.weixin.sdk.msg.in.event.InMenuEvent;
import com.jfinal.weixin.sdk.msg.in.event.InPoiCheckNotifyEvent;
import com.jfinal.weixin.sdk.msg.in.event.InQrCodeEvent;
import com.jfinal.weixin.sdk.msg.in.event.InShakearoundUserShakeEvent;
import com.jfinal.weixin.sdk.msg.in.event.InShakearoundUserShakeEvent.AroundBeacon;
import com.jfinal.weixin.sdk.msg.in.event.InTemplateMsgEvent;
import com.jfinal.weixin.sdk.msg.in.event.InVerifyFailEvent;
import com.jfinal.weixin.sdk.msg.in.event.InVerifySuccessEvent;
import com.jfinal.weixin.sdk.msg.in.event.ScanCodeInfo;
import com.jfinal.weixin.sdk.msg.in.speech_recognition.InSpeechRecognitionResults;

/**
 * TODO: 增加描述
 * 
 * @author yiz
 * @date 2016年8月3日 下午8:23:57
 * @version 1.0.0 
 * @copyright pycredit.cn 
 */
public class InMsgParser {
	/**
	 * 消息类型
	 * 1：text 文本消息
	 * 2：image 图片消息
	 * 3：voice 语音消息
	 * 4：video 视频消息
	 *	shortvideo 小视频消息
	 * 5：location 地址位置消息
	 * 6：link 链接消息
	 * 7：event 事件
	 */
	public static InMsg doParse(JSONObject jsonObject) {
		String toUserName = jsonObject.getString("ToUserName");
		String fromUserName = jsonObject.getString("FromUserName");
		Integer createTime = jsonObject.getInteger("CreateTime");
		String msgType = jsonObject.getString("MsgType");
		if ("text".equals(msgType))
			return parseInTextMsg(jsonObject, toUserName, fromUserName, createTime, msgType);
		if ("image".equals(msgType))
			return parseInImageMsg(jsonObject, toUserName, fromUserName, createTime, msgType);
		if ("voice".equals(msgType))
			return parseInVoiceMsgAndInSpeechRecognitionResults(jsonObject, toUserName, fromUserName, createTime,
					msgType);
		if ("video".equals(msgType))
			return parseInVideoMsg(jsonObject, toUserName, fromUserName, createTime, msgType);
		if ("shortvideo".equals(msgType)) //支持小视频
			return parseInShortVideoMsg(jsonObject, toUserName, fromUserName, createTime, msgType);
		if ("location".equals(msgType))
			return parseInLocationMsg(jsonObject, toUserName, fromUserName, createTime, msgType);
		if ("link".equals(msgType))
			return parseInLinkMsg(jsonObject, toUserName, fromUserName, createTime, msgType);
		if ("event".equals(msgType))
			return parseInEvent(jsonObject, toUserName, fromUserName, createTime, msgType);
		throw new RuntimeException("无法识别的消息类型 " + msgType + "，请查阅微信公众平台开发文档");
	}

	private static InMsg parseInTextMsg(JSONObject jsonObject, String toUserName, String fromUserName,
			Integer createTime, String msgType) {
		InTextMsg msg = new InTextMsg(toUserName, fromUserName, createTime, msgType);
		msg.setContent(jsonObject.getString("Content"));
		msg.setMsgId(jsonObject.getString("MsgId"));
		return msg;
	}

	private static InMsg parseInImageMsg(JSONObject jsonObject, String toUserName, String fromUserName,
			Integer createTime, String msgType) {
		InImageMsg msg = new InImageMsg(toUserName, fromUserName, createTime, msgType);
		msg.setPicUrl(jsonObject.getString("PicUrl"));
		msg.setMediaId(jsonObject.getString("MediaId"));
		msg.setMsgId(jsonObject.getString("MsgId"));
		return msg;
	}

	private static InMsg parseInVoiceMsgAndInSpeechRecognitionResults(JSONObject jsonObject, String toUserName,
			String fromUserName, Integer createTime, String msgType) {
		String recognition = jsonObject.getString("Recognition");
		if (StrKit.isBlank(recognition)) {
			InVoiceMsg msg = new InVoiceMsg(toUserName, fromUserName, createTime, msgType);
			msg.setMediaId(jsonObject.getString("MediaId"));
			msg.setFormat(jsonObject.getString("Format"));
			msg.setMsgId(jsonObject.getString("MsgId"));
			return msg;
		} else {
			InSpeechRecognitionResults msg = new InSpeechRecognitionResults(toUserName, fromUserName, createTime,
					msgType);
			msg.setMediaId(jsonObject.getString("MediaId"));
			msg.setFormat(jsonObject.getString("Format"));
			msg.setMsgId(jsonObject.getString("MsgId"));
			msg.setRecognition(recognition); // 与 InVoiceMsg 唯一的不同之处
			return msg;
		}
	}

	private static InMsg parseInVideoMsg(JSONObject jsonObject, String toUserName, String fromUserName,
			Integer createTime, String msgType) {
		InVideoMsg msg = new InVideoMsg(toUserName, fromUserName, createTime, msgType);
		msg.setMediaId(jsonObject.getString("MediaId"));
		msg.setThumbMediaId(jsonObject.getString("ThumbMediaId"));
		msg.setMsgId(jsonObject.getString("MsgId"));
		return msg;
	}

	private static InMsg parseInShortVideoMsg(JSONObject jsonObject, String toUserName, String fromUserName,
			Integer createTime, String msgType) {
		InShortVideoMsg msg = new InShortVideoMsg(toUserName, fromUserName, createTime, msgType);
		msg.setMediaId(jsonObject.getString("MediaId"));
		msg.setThumbMediaId(jsonObject.getString("ThumbMediaId"));
		msg.setMsgId(jsonObject.getString("MsgId"));
		return msg;
	}

	private static InMsg parseInLocationMsg(JSONObject jsonObject, String toUserName, String fromUserName,
			Integer createTime, String msgType) {
		InLocationMsg msg = new InLocationMsg(toUserName, fromUserName, createTime, msgType);
		msg.setLocation_X(jsonObject.getString("Location_X"));
		msg.setLocation_Y(jsonObject.getString("Location_Y"));
		msg.setScale(jsonObject.getString("Scale"));
		msg.setLabel(jsonObject.getString("Label"));
		msg.setMsgId(jsonObject.getString("MsgId"));
		return msg;
	}

	private static InMsg parseInLinkMsg(JSONObject jsonObject, String toUserName, String fromUserName,
			Integer createTime, String msgType) {
		InLinkMsg msg = new InLinkMsg(toUserName, fromUserName, createTime, msgType);
		msg.setTitle(jsonObject.getString("Title"));
		msg.setDescription(jsonObject.getString("Description"));
		msg.setUrl(jsonObject.getString("Url"));
		msg.setMsgId(jsonObject.getString("MsgId"));
		return msg;
	}

	// 解析各种事件
	private static InMsg parseInEvent(JSONObject jsonObject, String toUserName, String fromUserName, Integer createTime,
			String msgType) {
		String event = jsonObject.getString("Event");
		String eventKey = jsonObject.getString("EventKey");

		// 关注/取消关注事件（包括二维码扫描关注，二维码扫描关注事件与扫描带参数二维码事件是两回事）
		if (("subscribe".equals(event) || "unsubscribe".equals(event)) && StrKit.isBlank(eventKey)) {
			return new InFollowEvent(toUserName, fromUserName, createTime, msgType, event);
		}
		// 扫描带参数二维码事件之一		1: 用户未关注时，进行关注后的事件推送
		String ticket = jsonObject.getString("Ticket");
		if ("subscribe".equals(event) && StrKit.notBlank(eventKey) && eventKey.startsWith("qrscene_")) {
			InQrCodeEvent e = new InQrCodeEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			e.setTicket(ticket);
			return e;
		}
		// 扫描带参数二维码事件之二		2: 用户已关注时的事件推送
		if ("SCAN".equals(event)) {
			InQrCodeEvent e = new InQrCodeEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			e.setTicket(ticket);
			return e;
		}
		// 上报地理位置事件
		if ("LOCATION".equals(event)) {
			InLocationEvent e = new InLocationEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setLatitude(jsonObject.getString("Latitude"));
			e.setLongitude(jsonObject.getString("Longitude"));
			e.setPrecision(jsonObject.getString("Precision"));
			return e;
		}
		// 自定义菜单事件之一			1：点击菜单拉取消息时的事件推送
		if ("CLICK".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// 自定义菜单事件之二			2：点击菜单跳转链接时的事件推送
		if ("VIEW".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// 扫码推事件
		if ("scancode_push".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			String scanCodeInfoStr = jsonObject.getString("ScanCodeInfo");
			JSONObject scanCodeInfo = JSON.parseObject(scanCodeInfoStr);
			String scanType = scanCodeInfo.getString("ScanType");
			String scanResult = scanCodeInfo.getString("ScanResult");
			e.setScanCodeInfo(new ScanCodeInfo(scanType, scanResult));
			return e;
		}
		// 扫码推事件且弹出“消息接收中”提示框
		if ("scancode_waitmsg".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			String scanCodeInfoStr = jsonObject.getString("ScanCodeInfo");
			JSONObject scanCodeInfo = JSON.parseObject(scanCodeInfoStr);
			String scanType = scanCodeInfo.getString("ScanType");
			String scanResult = scanCodeInfo.getString("ScanResult");
			e.setScanCodeInfo(new ScanCodeInfo(scanType, scanResult));
			return e;
		}
		// 5. pic_sysphoto：弹出系统拍照发图，这个后台其实收不到该菜单的消息，点击它后，调用的是手机里面的照相机功能，而照相以后再发过来时，就收到的是一个图片消息了
		if ("pic_sysphoto".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// pic_photo_or_album：弹出拍照或者相册发图
		if ("pic_photo_or_album".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// pic_weixin：弹出微信相册发图器
		if ("pic_weixin".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// location_select：弹出地理位置选择器
		if ("location_select".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// media_id：下发消息（除文本消息）
		if ("media_id".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// view_limited：跳转图文消息URL
		if ("view_limited".equals(event)) {
			InMenuEvent e = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setEventKey(eventKey);
			return e;
		}
		// 模板消息是否送达成功通知事件
		if ("TEMPLATESENDJOBFINISH".equals(event)) {
			InTemplateMsgEvent e = new InTemplateMsgEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setMsgId(jsonObject.getString("MsgID"));
			e.setStatus(jsonObject.getString("Status"));
			return e;
		}
		// 群发任务结束时是否送达成功通知事件
		if ("MASSSENDJOBFINISH".equals(event)) {
			InMassEvent e = new InMassEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setMsgId(jsonObject.getString("MsgID"));
			e.setStatus(jsonObject.getString("Status"));
			e.setTotalCount(jsonObject.getString("TotalCount"));
			e.setFilterCount(jsonObject.getString("FilterCount"));
			e.setSentCount(jsonObject.getString("SentCount"));
			e.setErrorCount(jsonObject.getString("ErrorCount"));
			return e;
		}
		// 多客服接入会话事件
		if ("kf_create_session".equals(event)) {
			InCustomEvent e = new InCustomEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setKfAccount(jsonObject.getString("KfAccount"));
			return e;
		}
		// 多客服关闭会话事件
		if ("kf_close_session".equals(event)) {
			InCustomEvent e = new InCustomEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setKfAccount(jsonObject.getString("KfAccount"));
			return e;
		}
		// 多客服转接会话事件
		if ("kf_switch_session".equals(event)) {
			InCustomEvent e = new InCustomEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setKfAccount(jsonObject.getString("KfAccount"));
			e.setToKfAccount(jsonObject.getString("ToKfAccount"));
			return e;
		}
		// 微信摇一摇事件
		if ("ShakearoundUserShake".equals(event)) {
			InShakearoundUserShakeEvent e = new InShakearoundUserShakeEvent(toUserName, fromUserName, createTime,
					msgType);
			e.setEvent(event);

			String c = jsonObject.getString("ChosenBeacon");
			JSONObject ChosenBeacon = JSON.parseObject(c);
			e.setUuid(ChosenBeacon.getString("Uuid"));
			e.setMajor(Integer.parseInt(ChosenBeacon.getString("Major")));
			e.setMinor(Integer.parseInt(ChosenBeacon.getString("Minor")));
			e.setDistance(Float.parseFloat(ChosenBeacon.getString("Distance")));

			JSONArray jsonArray = jsonObject.getJSONObject("AroundBeacons").getJSONArray("AroundBeacon");
			if (jsonArray != null && jsonArray.size() > 0) {
				AroundBeacon aroundBeacon = null;
				List<AroundBeacon> aroundBeacons = new ArrayList<AroundBeacon>();
				for (int i = 0; i < jsonArray.size(); i++) {
					JSONObject obj = JSONObject.parseObject(jsonArray.getString(i));
					aroundBeacon = new AroundBeacon();
					aroundBeacon.setUuid(obj.getString("Uuid"));
					aroundBeacon.setMajor(obj.getInteger("Major"));
					aroundBeacon.setMinor(obj.getInteger("Minor"));
					aroundBeacon.setDistance(obj.getFloat("Distance"));
					aroundBeacons.add(aroundBeacon);
				}
				e.setAroundBeaconList(aroundBeacons);
			}
			return e;
		}

		// 资质认证成功 || 名称认证成功 || 年审通知 || 认证过期失效通知
		if ("qualification_verify_success".equals(event) || "naming_verify_success".equals(event)
				|| "annual_renew".equals(event) || "verify_expired".equals(event)) {
			InVerifySuccessEvent e = new InVerifySuccessEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setExpiredTime(jsonObject.getString("expiredTime"));
			return e;
		}
		// 资质认证失败 || 名称认证失败
		if ("qualification_verify_fail".equals(event) || "naming_verify_fail".equals(event)) {
			InVerifyFailEvent e = new InVerifyFailEvent(toUserName, fromUserName, createTime, msgType, event);
			e.setFailTime(jsonObject.getString("failTime"));
			e.setFailReason(jsonObject.getString("failReason"));
			return e;
		}
		// 门店在审核事件消息
		if ("poi_check_notify".equals(event)) {
			InPoiCheckNotifyEvent e = new InPoiCheckNotifyEvent(toUserName, fromUserName, createTime, msgType);
			e.setUniqId(jsonObject.getString("UniqId"));
			e.setPoiId(jsonObject.getString("PoiId"));
			e.setResult(jsonObject.getString("Result"));
			e.setMsg(jsonObject.getString("Msg"));
			return e;
		}

		throw new RuntimeException("无法识别的事件类型" + event + "，请查阅微信公众平台开发文档");
	}
}
